package com.lemon.components.ant.apimaker;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.assertj.core.util.Lists;
import org.springframework.beans.BeanUtils;

import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.ast.expr.SQLBinaryOpExpr;
import com.lemon.components.ant.apimaker.dto.ApiMakerDto;
import com.lemon.components.ant.apimaker.dto.ApiMakerReq;
import com.lemon.components.ant.apimaker.enums.CodePart;
import com.lemon.components.ant.apimaker.enums.FileWriteMode;
import com.lemon.components.ant.apimaker.enums.ResultType;
import com.lemon.components.ant.project.beans.ColumnInfo;
import com.lemon.components.ant.project.beans.TableInfo;
import com.lemon.components.ant.util.ConfigUtil;
import com.lemon.components.ant.util.FileUtil;
import com.lemon.components.ant.util.PathUtil;
import com.lemon.components.ant.util.TemplateUtil;
import com.lemon.components.ant.util.sqlparser.CustomerMySqlASTVisitorAdapter;
import com.lemon.components.ant.util.sqlparser.CustomerMySqlASTVisitorAdapter.SQLTableInfo;
import com.lemon.components.ant.util.sqlparser.WhereParser;
import com.lemon.components.docs.mysql.MysqlLocalTool;
import com.lemon.ui.codemaker.component.RecentlyFile;
import com.system.core.security.NameUtil;
import com.system.core.view.common.response.CommonResponse;

public class SQLMaker {
	
	private String serviceCommonPath;
	private String mybatisModelCommonPath;
	private String mybatisMapperCommonPath;
	private String mybatisXMLCommonPath;
	
	public List<ColumnInfo> getParam(ApiMakerReq req,List<SQLBinaryOpExpr> whereOpExpr) {
		List<ColumnInfo> columns = Lists.newArrayList();
		List<TableInfo> tables = MysqlLocalTool.getTableInfo(req.getProjectInfo());
		for(SQLBinaryOpExpr item : whereOpExpr) {
			String[] name = item.getLeft().toString().split("\\.");
			ColumnInfo column = MysqlLocalTool.getColumnInfo(tables, name[0], name[1]);
			columns.add(column);
		}
		return columns;
	}
	
	/**
	 * 通过SQL生成Java代码
	 * @param req
	 * @return
	 * @throws Exception
	 */
	public CommonResponse makeApiService(ApiMakerReq req) throws Exception {
		
		/**
		 * 获取各种保存路径
		 */
		serviceCommonPath=PathUtil.getInstance(req.getProjectInfo()).getServicePackagePath().getPath();
		mybatisModelCommonPath=PathUtil.getInstance(req.getProjectInfo()).getMybatisCustomizeModelPath();
		mybatisMapperCommonPath=PathUtil.getInstance(req.getProjectInfo()).getMybatisCustomizeMapperPath();
		mybatisXMLCommonPath=PathUtil.getInstance(req.getProjectInfo()).getMybatisCustomizeXMLPath();
		/**
		 * 从数据库获取元数据
		 */
		ResultSetMetaData resultSetMetaData = getResultSetMetaData(req);
		System.out.println(resultSetMetaData.getColumnLabel(1));
		/**
		 * 通过分析SQL的Where语句，获取查询参数，通过getParam方法
		 */
		List<SQLBinaryOpExpr> whereOpExpr = WhereParser.parse(req.getSql());
		ApiMakerDto result = ApiMakerDto.builder()
				.resultSetMetaData(resultSetMetaData)
				.params(getParam(req,whereOpExpr))
				.sqlWhere(whereOpExpr)
				.myModelPackage(PathUtil.getInstance(req.getProjectInfo()).getMyBatisBasePackage()+".mymodel")
				.myMapperPackage(PathUtil.getInstance(req.getProjectInfo()).getMyBatisBasePackage()+".mymapper")
				.dtoPackage(PathUtil.getInstance(req.getProjectInfo()).getServiceBasePackage()+"."+req.getServicePackageName()+".dto")
				.servicePackage(PathUtil.getInstance(req.getProjectInfo()).getServiceBasePackage()+"."+req.getServicePackageName())
				.build();
		/**
		 * 把请求参数一并存到result中，供模版使用
		 */
		BeanUtils.copyProperties(req, result);
		/**
		 * 通过页面的选择，决定生成哪些部分
		 */
		for(CodePart codePart : req.getCodepart()) {
			if(codePart == CodePart.DAO) {
				modelCode(req,result);
				myMapperCode(req,result);
				xmlCode(req,result);
				paramCode(req,result);
			} else if(codePart == CodePart.SERVICE) {
				dtoCode(req,result);
				if(req.isPager()) {
					requestCode(req,result);
					serviceCode(req,result);
				} else {
					requestCodeNoPage(req,result);
					serviceCodeNoPage(req,result);
				}
			} else if(codePart == CodePart.APICONTROLLER) {
				
			}
		}
		return CommonResponse.buildSuccessResult("success");
	}
	
	/**
	 * 生成Service的出参 DTO Java代码
	 * @param req
	 * @param result
	 * @throws Exception 
	 */
	private void dtoCode(ApiMakerReq req,ApiMakerDto result) throws Exception {
		String sourceFile = serviceCommonPath+"/"+req.getServicePackageName()+"/dto/" + NameUtil.getClassName(req.getBizName())+"Dto.java";
		TemplateUtil.getInstance(ConfigUtil.getInstance(RecentlyFile.configFilePath).getProjectInfo().getTemplatePath()).build(
				"/maven-project-template/service/apimaker/dto/DtoTemplate.java",
				sourceFile, 
				result);
		String importStr = "import "+result.getMyModelPackage()+"."+StringUtils.capitalize(result.getBizName())+"Model;";
		FileUtil.insertFile(importStr, 3, sourceFile);
	}
	
	/**
	 * 返回属性集合
	 * @param req
	 * @return
	 * @throws Exception
	 */
	private ResultSetMetaData getResultSetMetaData(ApiMakerReq req) throws Exception {
		Connection mycon = MysqlLocalTool.getDataSource(req.getProjectInfo()).getConnection();
		PreparedStatement preparedStatement = mycon.prepareStatement(req.getSql());
		ResultSet resultSet =preparedStatement.executeQuery();
		ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
		return resultSetMetaData;
	}
	
	public List<SQLTableInfo> getTables(String sql) {
		try {
			SQLStatement sqlStatement = SQLUtils.parseSingleMysqlStatement(sql);
			CustomerMySqlASTVisitorAdapter customerMySqlASTVisitorAdapter = new CustomerMySqlASTVisitorAdapter();
			sqlStatement.accept(customerMySqlASTVisitorAdapter);
			return customerMySqlASTVisitorAdapter.getTableInfos();
		} catch (Exception e) {
			System.out.println("出错："+e.getMessage());
		}
		return null;
	}
	
	/**
	 * 生成Mybatis的出参Model Java代码
	 * @param req
	 * @param result
	 */
	private void modelCode(ApiMakerReq req,ApiMakerDto result) {
		TemplateUtil.getInstance(ConfigUtil.getInstance(RecentlyFile.configFilePath).getProjectInfo().getTemplatePath()).build(
				"/maven-project-template/service/apimaker/dto/ModelTemplate.java",
				mybatisModelCommonPath+"/" + NameUtil.getClassName(req.getBizName())+"Model.java", 
				result);
	}
	/**
	 * 生成MyBatis的接口Java代码
	 * @param req
	 * @param result
	 * @throws Exception
	 */
	private void myMapperCode(ApiMakerReq req,ApiMakerDto result) throws Exception {
		String sourceFile = mybatisMapperCommonPath+"/My"+StringUtils.capitalize(req.getServName())+"Mapper.java";
		String insertStr;
		String importStr;
		String bizNamecap = StringUtils.capitalize(result.getBizName());
		insertStr = "\n\t/**\n\t * "+result.getComments()+"\n\t **/";
		if(req.getResultType()==ResultType.ResultSet) {
			insertStr += "\n\tpublic List<"+bizNamecap+"Model> select"+bizNamecap+"("+bizNamecap+"Param param);";
		} else {
			insertStr += "\n\tpublic "+bizNamecap+"Model get"+bizNamecap+"("+bizNamecap+"Param param);";
		}
		importStr ="import "+result.getMyModelPackage()+"."+StringUtils.capitalize(result.getBizName())+"Param;\n";
		importStr +="import "+result.getMyModelPackage()+"."+StringUtils.capitalize(result.getBizName())+"Model;";
		FileUtil.insertFile(insertStr, FileUtil.totalRowFile(sourceFile), sourceFile);
		FileUtil.insertFile(importStr, 3, sourceFile);
	}
	
	/**
	 * 生成mybatis的入参Java代码
	 * @param req
	 * @param result
	 */
	private void paramCode(ApiMakerReq req,ApiMakerDto result) {
		TemplateUtil.getInstance(ConfigUtil.getInstance(RecentlyFile.configFilePath).getProjectInfo().getTemplatePath()).build(
				"/maven-project-template/service/apimaker/dto/ParamTemplate.java",
				mybatisModelCommonPath+"/" + NameUtil.getClassName(req.getBizName())+"Param.java", 
				result);
	}
	
	/**
	 * 生成Service的入参Java代码
	 * @param req
	 * @param result
	 */
	private void requestCode(ApiMakerReq req,ApiMakerDto result) {
		TemplateUtil.getInstance(ConfigUtil.getInstance(RecentlyFile.configFilePath).getProjectInfo().getTemplatePath()).build(
				"/maven-project-template/service/apimaker/dto/RequestTemplate.java",
				serviceCommonPath+"/"+req.getServicePackageName()+"/dto/" + NameUtil.getClassName(req.getBizName())+"Req.java", 
				result);
	}
	private void requestCodeNoPage(ApiMakerReq req,ApiMakerDto result) {
		TemplateUtil.getInstance(ConfigUtil.getInstance(RecentlyFile.configFilePath).getProjectInfo().getTemplatePath()).build(
				"/maven-project-template/service/apimaker/dto/RequestTemplateNoPage.java",
				serviceCommonPath+"/"+req.getServicePackageName()+"/dto/" + NameUtil.getClassName(req.getBizName())+"Req.java", 
				result);
	}
	
	/**
	 * 生成服务Java代码
	 * @param req
	 * @param result
	 * @throws Exception
	 */
	private void serviceCode(ApiMakerReq req,ApiMakerDto result) throws Exception {
		if(req.getFileWriteMode() == FileWriteMode.APPEND) {
			String sourceFile = serviceCommonPath+"/"+req.getServicePackageName()+"/"+StringUtils.capitalize(req.getServName())+"Service.java";
			String insertStr = TemplateUtil.getInstance(ConfigUtil.getInstance(RecentlyFile.configFilePath).getProjectInfo().getTemplatePath()).print(
					"/maven-project-template/service/apimaker/bizTemplate-snap.java", 
					result);
			
			String importStr ="import "+result.getMyModelPackage()+"."+StringUtils.capitalize(result.getBizName())+"Param;\n";
			importStr +="import "+result.getMyModelPackage()+"."+StringUtils.capitalize(result.getBizName())+"Model;\n";
			importStr +="import "+result.getDtoPackage()+"."+StringUtils.capitalize(result.getBizName())+"Req;\n";
			importStr +="import "+result.getDtoPackage()+"."+StringUtils.capitalize(result.getBizName())+"Dto;\n";
			FileUtil.insertFile(insertStr, FileUtil.totalRowFile(sourceFile), sourceFile);
			FileUtil.insertFile(importStr, 3, sourceFile);
		} else {
			TemplateUtil.getInstance(ConfigUtil.getInstance(RecentlyFile.configFilePath).getProjectInfo().getTemplatePath())
				.build("/maven-project-template/service/apimaker/bizTemplate-clazz.java", 
						serviceCommonPath+"/"+req.getServicePackageName()+"/" + StringUtils.capitalize(req.getServName())+"Service.java", 
						result);
		}
	}
	
	private void serviceCodeNoPage(ApiMakerReq req,ApiMakerDto result) throws Exception {
		if(req.getFileWriteMode() == FileWriteMode.APPEND) {
			String sourceFile = serviceCommonPath+"/"+req.getServicePackageName()+"/"+StringUtils.capitalize(req.getServName())+"Service.java";
			String insertStr = TemplateUtil.getInstance(ConfigUtil.getInstance(RecentlyFile.configFilePath).getProjectInfo().getTemplatePath()).print(
					"/maven-project-template/service/apimaker/bizTemplate-snap-nopage.java", 
					result);
			
			String importStr ="import "+result.getMyModelPackage()+"."+StringUtils.capitalize(result.getBizName())+"Param;\n";
			importStr +="import "+result.getMyModelPackage()+"."+StringUtils.capitalize(result.getBizName())+"Model;\n";
			importStr +="import "+result.getDtoPackage()+"."+StringUtils.capitalize(result.getBizName())+"Req;\n";
			importStr +="import "+result.getDtoPackage()+"."+StringUtils.capitalize(result.getBizName())+"Dto;\n";
			FileUtil.insertFile(insertStr, FileUtil.totalRowFile(sourceFile), sourceFile);
			FileUtil.insertFile(importStr, 3, sourceFile);
		} else {
			TemplateUtil.getInstance(ConfigUtil.getInstance(RecentlyFile.configFilePath).getProjectInfo().getTemplatePath())
			.build("/maven-project-template/service/apimaker/bizTemplate-clazz-nopage.java", 
					serviceCommonPath+"/"+req.getServicePackageName()+"/" + StringUtils.capitalize(req.getServName())+"Service.java", 
					result);
		}
	}
	
	/**
	 * 生成MyBatis自定义SQL的XML文件
	 * @param req
	 * @param result
	 * @return
	 * @throws Exception 
	 */
	private void xmlCode(ApiMakerReq req,ApiMakerDto result) throws Exception {
		String sourceFile = mybatisXMLCommonPath+"/My"+StringUtils.capitalize(req.getServName())+"Mapper.xml";
		String insertStr = TemplateUtil.getInstance(ConfigUtil.getInstance(RecentlyFile.configFilePath).getProjectInfo().getTemplatePath()).print(
				"/maven-project-template/service/apimaker/mybatis/myMapper.xml", 
				result);
		FileUtil.insertFile(insertStr, FileUtil.totalRowFile(sourceFile), sourceFile);
	}
}